<html>
    <head>
        <title>应用程序启动</title>
    </head>
    <body>
        <script>
            // ABP 应用程序启动

                    /*
                        你通常使用 ABP Cli 的  ： abp new 命令来使用 "预构建的启动解决方案模板" 之一来开始。
                        当你这样做时，你通常不需要了解ABP如何与你的应用程序集成或如何配置和初始化的详细信息。
                        启动模板还附带基本的ABP包，并且为你预安装和配置了"应用程序模块"。
                    */

                    /*
                        虽然ABP有很多特性和集成，但它是作为一个轻量级和模块化的框架构建的。
                        它由数百个 "Nuget 包" 和 Npm 包组成，因此你只能使用你需要的功能。

                        如果你查看使用用空的 asp.net core mvc/razor Page 应用程序集成abp 的文档： "快速开始---其他---空asp.net core 应用"
                        你会看到从头到尾讲abp安装到一个空的 asp.net core 项目中是多么容易，
                        你只需要安装一个 NuGet包并进行一些小的更改就好。

                    */


                // 一、安装abp
                                /*
                                    一个 .net 控制台应用程序是最简单的应用程序，所以使用控制台程序来演示ABP的安装过程。

                                    1. 创建一个新的控制台应用程序。

                                    2. 使用abp cli 安装abp (添加NuGet 包): 
                                                abp addppackage Volo.Abp.core

                                        或者 在项目的根目录下运行以下命令:
                                                dotnet add package Volo.Abp.Core

                                    3.添加NuGet包后，我们应该为应用程序创建一个 "根模块类"：

                                            using Volo.Abp.Modularity; // 引入ABP模块化系。
                                            namespace MyConsoleDemo
                                            {
                                                public class MyConsoleDemoModule : AbpModule  // 继承AbpModule类，并命名为MyConsoleDemoModule。q
                                                {
                                                }
                                            }

                                            这是一个从 AbpModule 类派生的空类。它将是你控制应用程序的依赖关系、实现配置和启动/关闭逻辑的主类。

                                    4.更改 Program.cs 文件
                                                using MyConsoleDemo;
                                                using Volo.Abp;

                                                // 1: Create the ABP application container
                                                using var application = await AbpApplicationFactory.CreateAsync<MyConsoleDemoModule>();

                                                // 2: Initialize/start the ABP (and all the modules)
                                                await application.InitializeAsync();

                                                Console.WriteLine("ABP has been started...");

                                                // 3: Stop the ABP (and all the modules)
                                                await application.ShutdownAsync();
                                */

                                // 就是这么简单，现在 abp 已经在你的应用程序中安装、集成、启动和停止。
                                // 从现在开始你可以在需要的时候安装将 "ABP包"安装到你的应用程序中。
                    


                // 二、 安装框架模块包  (Installing a Framework Package)
                                /*
                                        如果你想从你的.net 应用程序中发送电子邮件，你可以使用.net 的标准 SmtpClient类。
                                        ABP还提供了IEamilSender服务，该服务简化了发送电子邮件的操作，并在中心位置配置电子邮件设置。
                                        
                                        1、如果你想使用它，你应该在你的项目中安装 Volo.Abp.Email NuGet 包。
                                        
                                              dotnet add package Volo.Abp.Emailing

                                        2、安装后，你还需要从模块的“模块类”中指定模块依赖项( eg: MyConsoleDemoModule 类中)：
                                                
                                                using Volo.Abp.Emailing; // 引入ABP邮件模块。
                                                using Volo.Abp.Modularity; // 引入ABP模块化系。

                                                namespace MyConsoleDemo
                                                {
                                                    [DependsOn(typeof(AbpEmailingModule))] // Added the module dependency
                                                    public class MyConsoleDemoModule : AbpModule
                                                    {
                                                    }
                                                }
                                        
                                        在模块类的头部添加了[DependsOn(typeof(AbpEmailingModule))] 属性，这告诉ABP框架你的应用程序依赖于 AbpEmailingModule。
                                        现在，可以在Program.cs 中使用 IEmailSender 服务        
                                        
                                        就是这么简单。安装 abp 模块的NuGet包，添加模块依赖项 (使用 [DependsOn]特性)，就可以使用任何abp的内置模块。

                                        ABP CLi 已经有一个特殊的命令来添加 ABP 的NuGet包，并使用这个命令会自动添加[DependsOn]特性：
                                                    abp add-package Volo.Abp.Emailing
                                                （建议使用 abp add-package 命令而不是手动执行）
                                */

                // 三、AbpApplicationFactory 类
                                /*
                                        AbpApplicationFactory 是创建ABP应用程序容器的"工厂类"。它提供了具有多个重载的单个静态 CreateAsync 方法。
                                        现在，让我们看看在什么情况下使用这些重载？

                                        1、第一个重载，获取一个通用模块类参数：
                                                    AbpApplicationFactory.CreateAsync<MyConsoleDemoModule>();
                                                泛型参数应该是当前应用程序的 "根模块类"。所有其他模块都被解析为该模块的依赖项。

                                        2、第二个重载,将根模块类的Type作为参数：
                                                    AbpApplicationFactory.CreateAsync(typeof(MyConsoleDemoModule));

                                        这两个重载的工作方式完全相同。因此二选一就好。


                                        如果你是用上述方法之一，ABP将会创建一个“内部服务集合” IserviceCollection 和 一个 "内部服务提供者" IServiceProvider，来在abp应用程序
                                        内部设置 "依赖注入系统"。
                                        请注意，我们使用了安装框架包部分中的application.ServiceProvider属性来解析依赖注入系统中的IEmailSender服务：

                                                using Microsoft.Extensions.DependencyInjection;
                                                using MyConsoleDemo;
                                                using Volo.Abp;

                                                // 1: 手动创建服务集合 IServiceCollection
                                                IServiceCollection services = new ServiceCollection();

                                                // 2: 创建ABP应用程序时，将 "服务集合" 传递给abp应用程序
                                                using var application = await AbpApplicationFactory
                                                    .CreateAsync<MyConsoleDemoModule>(services);

                                                // 3: 手动创建服务提供者对象（IOC容器） IServiceProvider
                                                IServiceProvider serviceProvider = services.BuildServiceProvider();

                                                // 4: 初始化abp应用程序时，将 "服务提供者对象" 传递给abp应用程序
                                                await application.InitializeAsync(serviceProvider);

                                                Console.WriteLine("ABP has been started...");

                                                await application.ShutdownAsync();   
                                                
                                        这里我们使用了 .net 的标准依赖注入容器:  services.BuildServiceProvider()创建标准服务容器(IOC容器)。
                                        但是，ABP提供了另一种扩展方法: BuildServiceProviderFromFactory()

                                        3、第三个重载，它将模块类名作为Type参数和IServiceCollection对象：
                                                            using var application = await AbpApplicationFactory
                                                            .CreateAsync(typeof(MyConsoleDemoModule), services);

                                            （所有 CreateAsynac方法重载都有Creat对应项。）
                                */



                // 四、AbpApplicationCreationOptions abp应用程序创建选项类
                                /*
                                       所有CreateAsync重载都可以获得可选的 Action<AbpApplicationCreationOptions> 参数来配置应用程序创建过程中的选项：
                                            
                                            using var application = await AbpApplicationFactory
                                                        .CreateAsync<MyConsoleDemoModule>(options=>{
                                                            options.ApplicationName ="MyApp"    
                                                        })

                                       在这里，我们已经传递了一个 lambda 方法来配置ApplicationName选项属性。以下是所有选项的列表：
                                              ①、ApplicationName：应用程序的人类可读名称。它是应用程序的唯一值。
                                              ②、Configuration：可用于设置托管系统未提供的应用程序配置。ASP.NETCore和其他. NET托管应用程序不需要它。但是，如果你已经将 
                                              ②、Environment：应用程序的环境名称。    
                                              ④、PlugInSources：插件源列表
                                              ⑤、Services：可用于注册服务依赖项的IServiceCollection对象。你通常不需要它，因为你在模块类中配置服务。但是，它可以在为AbpApplicationCreationOptions类编写扩展方法时使用。     
                                */                    
                                /*
                                    1、ApplicationName 选项：
                                            如上所述，ApplicationName选项是应用程序的人类可读名称。它是应用程序的唯一值。
                                             ApplicationName被ABP在几个地方用来区分应用程序。
                                                例如： 审计日志系统在相关应用程序写入的每个审计日志记录中保存了ApplicationName，因此你可以了解哪个应用程序创建了审计日志条目。
                                                      因此，如果你的系统由多个应用程序（如微服务解决方案）组成，它们正在将审计日志保存到一个点，你应该确保每个应用程序都有不同的ApplicationName。
                                            
                                            ApplicationName 的默认值一般是当前整个程序集的名称 (通常是 .net 解决方案中的项目名称)。这适用于大多数情况，因为每个应用程序通常都有一个唯一的条目程序集名称。
                                            
                                            有两种方法可以设置应用程序名称：
                                               ①、在appsettings.json 文件中设置：
                                                        {
                                                            "ApplicationName": "Services.Ordering"
                                                        }

                                               ②、或者在创建ABP应用程序时设置AbpApplicationCreationOptions.ApplicationName：
                                                        await builder.AddApplicationAsync<OrderingServiceHttpApiHostModule>(options =>
                                                        {
                                                            options.ApplicationName = "Services.Ordering";
                                                        });

                                            
                                    2、IApplicationInfoAccessor 接口
                                             如果你需要稍后在解决方案中访问ApplicationName，你可以注入IApplicationInfoAccessor服务并从其ApplicationName属性中获取值。
                                             IApplicationInfoAccessor还提供了一个InstanceId值，这是应用程序启动时生成的随机GUID值。你可以使用该值来区分应用程序实例

                                */

                        // 五、IAbpApplication 接口
                                /*
                                    AbpApplicationFactory从其CreateAsync（或Create）方法返回一个IAbpApplication对象。
                                    IAbpApplication是ABP应用程序的主容器。它已经被注册到依赖注入系统，因此你可以在服务中注入IAbpApplication以使用其属性和方法。

                                    以下是你可能想知道的IAbpApplication属性列表：
                                            ①、StartupModuleType：获取创建应用程序容器时使用的应用程序的根模块（在AbpApplicationFactory.CreateAsync方法上）。
                                            ②、Services：所有服务注册的列表（IServiceCollection对象）。
                                                         应用程序初始化后，你不能向该集合添加新服务（你实际上可以添加，但不会有任何效果）。
                                            ③、ServiceProvider：对应用程序使用的根服务提供者的引用。（这在初始化应用程序之前不能使用）
                                                 如果你需要从那个IServiceProvider对象解析非单例服务，请始终创建一个新的服务范围，并在使用后将其处置。否则，你的应用程序将出现内存泄漏问题。有关服务范围的更多信息，请参阅依赖注入文档的释放/处置服务部分。
                                            ④、Modules：加载到当前应用程序中的所有模块的只读列表。
                                                        或者，如果你需要访问应用程序代码中的模块列表，你可以注入IModuleContainer服务。


                                           IAbpApplication接口扩展了IApplicationInfoAccessor接口，因此你可以从中获取ApplicationName和InstanceId值。
                                           但是，如果你只需要访问这些属性，请注入并使用IApplicationInfoAccessor服务。     

                                           IAbpApplication是一次性的。始终在退出应用程序之释放它。
                                */


                    // 六、IAbpHostEnvironment 虚拟主机 
                                /*
                                    有时候，在创建应用程序的同时，我们需要获取当前的"托管环境"并据此采取行动，
                                    在这种情况下，我们可以在最终的应用程序中使用一些服务，如IWebHostGEF或IWebAssemblyHostEnvironment. NET提供的。

                                    但是，我们不能在一个类库中使用这些服务，该类库由最终应用程序使用。
                                    ABP提供了IAbpHostEnvironment服务，它允许你随时获取当前环境名称。
                                    IAbpHostEnvironment被ABP在几个地方用于执行环境的特定操作，例如，ABP为某些服务减少了Development环境上的缓存持续时间。


                                    IAbpHostEnvironment按以下顺序获取当前"环境名称"：
                                                1、获取和设置在AbpApplicationCreationOptions中指定的环境名称。
                                                2、如果环境名称未在AbpApplicationCreationOptions中指定，
                                                    则尝试从ASP.NETCore&Blazor WASM应用程序的IWebHostEnvironment或IWebAssemblyHostEnvironment服务获取环境名称。
                                                3、如果未指定环境名称或无法从服务中获取环境名称，则将环境名称设置为生产。

                                    你可以在创建ABP应用程序时配置AbpApplicationCreationOptions 选项类，并为 Environment 属性设置环境名称。
                                    你可以在解决方案中这都要 AddApplication 或 AddApplicationAsync 调用，并设置 Environment 选项属性：
                                                await builder.AddApplicationAsync<MyConsoleDemoModule>(options =>{
                                                     options.Environment = Environments.Staging; //设置当前应用程序的运行环境。 
                                                });

                                    然后，无论何时需要获取当前环境名称或检查环境，都可以使用 IAbpHostEnvironment 接口：
                                                public class MyDemoService
                                                {
                                                    private readonly IAbpHostEnvironment _abpHostEnvironment;
                                                    
                                                    public MyDemoService(IAbpHostEnvironment abpHostEnvironment)
                                                    {
                                                        _abpHostEnvironment = abpHostEnvironment;
                                                    }

                                                    public void MyMethod()
                                                    {
                                                        var environmentName = _abpHostEnvironment.EnvironmentName;

                                                        if (_abpHostEnvironment.IsDevelopment()) {  } 

                                                        if (_abpHostEnvironment.IsStaging()) {  }

                                                        if (_abpHostEnvironment.IsProduction()) {  }

                                                        if (_abpHostEnvironment.IsEnvironment("custom-environment")) {  }
                                                    }
                                                }
                                */


                // 七、.net 通用主机 和 asp.net Core集成
                                /*
                                    AbpApplicationFactory可以创建一个独立的ABP应用程序容器,而无需任何外部依赖。
                                    但是，在大多数情况下，你会希望将其与 ".net的通用主机" 或 "asp.net core"集成。
                                    对于这种用法，ABP提供了内置的扩展方法来轻松创建一个与这些系统很好集成的ABP应用程序容器。

                                    "空 asp.net core MVC/Razor Pages 应用程序快速开始文档"清楚地解释了如何在 空asp.net core MVC/Razor Pages应用程序中集成ABP应用程序容器。

                                    你还可以创建一个控制台应用程序以查看它是ABP应用程序容器是如何与 ".net 通用主机" 集成的。
                                */
        </script>
    </body>
</html>